package com.hmall.order.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hmall.common.client.ItemClient;
import com.hmall.common.client.UserClient;
import com.hmall.common.dto.OrderDto;
import com.hmall.common.pojo.Address;
import com.hmall.common.pojo.Item;
import com.hmall.order.mapper.OrderDetailMapper;
import com.hmall.order.mapper.OrderLogisticsMapper;
import com.hmall.order.mapper.OrderMapper;
import com.hmall.order.pojo.Order;
import com.hmall.order.pojo.OrderDetail;
import com.hmall.order.pojo.OrderLogistics;
import com.hmall.order.service.IOrderService;
import com.hmall.utils.UserThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final Snowflake snowflake = new Snowflake(1, 1);
    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 创建订单
     *
     * @param orderDto
     * @return
     */
    @Override
    @Transactional
    public Long saveOrder(OrderDto orderDto) {
        //雪花算法生成订单号
        long orderId = snowflake.nextId();
        //根据商品id查询商品信息
        Item item = itemClient.getById(orderDto.getItemId());
        //计算总价
        Long totalFee = item.getPrice() * orderDto.getNum();

        //封装Order对象.初始支付状态为未支付
        Order order = Order.builder()
                .id(orderId)
                .totalFee(Integer.parseInt(totalFee.toString()))
                .paymentType(orderDto.getPaymentType())
                .userId(Long.valueOf(UserThreadLocal.get()))
                .status(1)
                .createTime(LocalDateTime.now())
                .closeTime(LocalDateTime.now().plusMinutes(30))
                .updateTime(LocalDateTime.now())
                .build();
        int insert = orderMapper.insert(order);
        if (insert > 0) {
            //构造订单详情对象
            OrderDetail orderDetail = OrderDetail.builder()
                    .orderId(orderId)
                    .itemId(orderDto.getItemId())
                    .num(orderDto.getNum())
                    .title(item.getName())
                    .price(item.getPrice())
                    .spec(item.getSpec())
                    .image(item.getImage())
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();

            //保存订单详情
            orderDetailMapper.insert(orderDetail);
            //调用用户服务查出收货地址
            Address address = userClient.findAddressById(orderDto.getAddressId());
            //封装OrderLogistics对象
            OrderLogistics orderLogistics = OrderLogistics.builder()
                    .orderId(orderId)
                    .contact(address.getContact())
                    .phone(address.getMobile())
                    .province(address.getProvince())
                    .city(address.getCity())
                    .town(address.getTown())
                    .street(address.getStreet())
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
            orderLogisticsMapper.insert(orderLogistics);
            //扣减库存
            itemClient.updateStock(orderDto.getItemId(), orderDto.getNum());
            log.info("订单创建成功");
//            String orderIdStr = String.valueOf(orderId);
//            try {
//                return objectMapper.writeValueAsString(orderId);
//            } catch (JsonProcessingException e) {
//                throw new RuntimeException(e);
//            }
            //发送消息到死信队列
            sendMessage(orderId);

            return orderId;

        } else {
            throw new RuntimeException("订单创建失败");
        }

    }

    /**
     * 发送延迟消息给死信队列
     * @param orderId
     */
    public void sendMessage(Long orderId) {
        //将订单id转换为String
        String orderIdStr = String.valueOf(orderId);
        //创建消息的id,用于唯一标识消息
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        //消息发送到交换机成功失败的回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    log.info("消息发送order.exchange成功");
                } else {
                    log.info("消息发送order.exchange失败");
                }
            }
        });
        //消息发送到队列queue的失败回调
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                log.info("消息发送到队列失败");
            }
        });
        //构建消息对象
        Message message = MessageBuilder.withBody(orderIdStr.getBytes())
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .setExpiration("30*60000")
                //.setExpiration("5000")
                //.setHeader("x-delay",30*60000)//延时队列延时毫秒数
                .build();
        //调用rabbitTemplate发送消息
        rabbitTemplate.convertAndSend("order.exchange", "order.routing", message, correlationData);
    }

    /**
     * 查询超时订单id
     *
     * @return
     */
    @Override
    public List<Order> selectOrderByStatusAndTime() {
        LambdaQueryWrapper<Order> queryWrapper = Wrappers.<Order>lambdaQuery()
                .eq(Order::getStatus, 1)
                //超时
                .lt(Order::getCreateTime, LocalDateTime.now().plusMinutes(-30));
      return    orderMapper.selectList(queryWrapper);

    }

    /**
     * 根据id修改订单状态
     *
     * @param id
     * @param i
     */
    @Override
    public void updateStatusById(Long id, int i) {
        this.lambdaUpdate().set(Order::getStatus, i)
                .eq(Order::getId, id)
                .update();
    }
}
